import { user } from "@/request"
import { useUserStore } from "@/store"
import { App } from "vue"
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router"
import Login from "../views/Login/index.vue"

const routes: RouteRecordRaw[] = [
    {
        path: "/",
        redirect: "/index"
    },
    {
        path: "/login",
        name: "login",
        // 一般来说，项目的第一个进入的页面不要使用 路由懒加载
        component: Login
    },
]

const router = createRouter({
    history: createWebHashHistory(),
    routes
})

// 路由前置导航守卫
router.beforeEach((to, from, next) => {
    let token = localStorage.getItem('token')
    let useUser = useUserStore()
    // console.log(router.getRoutes());

    // 如果没有登录，只让用户访问 login
    if (!token && to.path !== "/login") {
        next("/login")
    }
    // 如果已经是登录状态，用户手动访问 /login  强制跳回  之前的页面
    else if (token && to.path.toLocaleLowerCase() === "/login") {
        next(from.path)
    }
    // 无论是登录后,还是刷新  只要token还在 就需要保持用户的菜单信息也一直存在
    // 所以当每一次路由跳转的时候，都检查一下用户的菜单数据是否丢失，如果丢失了就重新请求存到pinia里
    else if (token && useUser.menus.length === 0 && router.getRoutes().length === 2 && (from.path === "/" || from.path === "/login")) {
        // 发送请求请求用户信息
        user.userInfoApi().then(res => {
            // 一切操作都基于请求成功的前提下
            if (res.code === 200) {
                useUser.menus = res.data.menus
                useUser.username = res.data.username

                // 需要深拷贝一层,如果不拷贝 那么和pinia里面的数组都是引用类型,会互相影响到
                // 因为nav渲染出来的列表跟实际上存在的路由不是一样的,所以分开进行处理渲染
                const newMenus: IMenu[] = JSON.parse(JSON.stringify(res.data.menus))
                // console.log(newMenus);

                const parent: IActiveMenus[] = newMenus.filter(item => item.parentId === 0)
                newMenus.forEach(item => {
                    const p = parent.find(citem => citem.id === item.parentId)
                    if (p) {
                        if (!p.children) {
                            p.children = []
                        }
                        p.children.push(item)
                    }
                })


                parent.forEach((parent) => {
                    // 遍历已经处理好的数据,动态添加路由
                    // 在登录成功之后 根据用户的权限动态的生成用户所能访问的路由
                    // 生成动态路由 - addRoute方法是专门用来动态添加路由配置的
                    let route: RouteRecordRaw = {
                        path: "/" + parent.name,
                        name: parent.name,
                        component: () => import("../views/Home/index.vue"),
                        children: [],
                        meta: {
                            title: parent.title,
                        },
                    }
                    parent.children?.forEach((child) => {
                        route.children?.push(
                            {
                                path: `/${parent.name}/${child.name}`,
                                name: child.name,
                                component: () => import(`../views/${parent.name}/${child.name}.vue`),
                                meta: {
                                    title: child.title,
                                },
                            }
                        )
                    })
                    // 这是一个增加路由的方法
                    router.addRoute(route)
                    // 如果to.path的路由是本来就已经存在的话，就不需要带参数，不然会报错
                    // 所以当我们从/login到/index的时候，我们就可以直接放行
                })

                // 只需要添加一次
                // 因为要使用户在未登录的时候,除了login其他页面的路由是不存在的,所以首页的路由也在用户成功登录之后再去添加
                router.addRoute(
                    {
                        path: "/",
                        name: "home",
                        redirect: "/login",
                        component: () => import("../views/Home/index.vue"),
                        children: [
                            {
                                path: "/index",
                                name: "index",
                                component: () => import("../views/index/index.vue")
                            }
                        ],
                    }
                )
                // from.path === "/login" ? next() : next(to.path)
                // 如果只是单纯的写next()相当于放行,放行是不会重新进入beforeEach的
                // 如果带参数的话,next(参数)相当于跳转就会重新进入beforeEach
                // 而这里使用参数的形式是因为添加路由也是需要时间的,如果直接使用next()放行的话,有可能路由还没添加完就可以放行进入页面了,会导致找不到该路由
                next(to.fullPath);
            }
        })
    }
    else {
        next()
    }
})

export default (app: App<Element>) => {
    app.use(router)
}

export { router }